
module Control(Start,iOpcode,iFunction,iReset,iClk,oPCWriteCond,oPCWrite,oIorD,oMemRead,oMemWrite,oMemtoReg,oIRWrite,oRegDst,oRegWrite,oALUSrcA,oALUSrcB,oALUOp,oPCSource);

input [31:26]iOpcode;	// Opcode part which connected [31:26] Instruction
input [5:0]iFunction;	// Function part which connected [5:0] Instruction
input iReset;		// Reset
input iClk;		// Clock
input Start;		// Start Button

output oPCWriteCond;	// PC
output oPCWrite;	// PC
output oIorD;		// Selector of Mux between PC and Memory
output oMemRead;	// Read Enable of Memory
output oMemWrite;	// Write Enable of Memory
output oMemtoReg;	// Selector of Mux between MemoryDataRegister and Regusters 
output oIRWrite;	// Write Enable of InstructionRegister
output oRegDst;		// Selector of Mux between InstructionRegister and Regusters 
output oRegWrite;	// Write Enable of Registers
output oALUSrcA;	// Selector of Mux between A and ALU
output [1:0]oALUSrcB;	// Selector of Mux between B and ALU 
output [2:0]oALUOp;	// ALUOp
output [1:0]oPCSource;	// Selector of Mux between ALU and PC

wire [11:0]D;		// input of D FF
wire [11:0]Q;		// output of D FF
wire Add,Sub,Slt;	// Function

/* state diagram */
D_FF DFF_0(D[0],iClk,Q[0],iReset);	// Instruction Fetch
D_FF DFF_1(D[1],iClk,Q[1],iReset);	// Instruction Decode
D_FF DFF_2(D[2],iClk,Q[2],iReset);	// Execution
D_FF DFF_3(D[3],iClk,Q[3],iReset);	// Memory Address Computation
D_FF DFF_4(D[4],iClk,Q[4],iReset);	// Beq
D_FF DFF_5(D[5],iClk,Q[5],iReset);	// Ori
D_FF DFF_6(D[6],iClk,Q[6],iReset);	// Jump
D_FF DFF_7(D[7],iClk,Q[7],iReset);	// R-type Completion
D_FF DFF_8(D[8],iClk,Q[8],iReset);	// Memory access(Write)
D_FF DFF_9(D[9],iClk,Q[9],iReset);	// Memory access(Read)
D_FF DFF_10(D[10],iClk,Q[10],iReset);	// Wite Back
D_FF DFF_11(D[11],iClk,Q[11],iReset);	// Beq Completion

/* input of state */
assign D[0] = Start | Q[7] | Q[10] | Q[9] | Q[4] | Q[11] | Q[6];
assign D[1] = Q[0];
assign D[2] = Q[1] & ~iOpcode[31] & ~iOpcode[30] & ~iOpcode[29] & ~iOpcode[28] & ~iOpcode[27] & ~iOpcode[26]; 
assign D[3] = Q[1] & iOpcode[31] & ~iOpcode[30] &  ~iOpcode[28] & iOpcode[27] & iOpcode[26];  
assign D[4] = Q[1] & ~iOpcode[31] & ~iOpcode[30] & ~iOpcode[29] & iOpcode[28] & ~iOpcode[27] & ~iOpcode[26];  
assign D[5] = Q[1] & ~iOpcode[31] & ~iOpcode[30] & iOpcode[29] & iOpcode[28] & iOpcode[27] & ~iOpcode[26];   
assign D[6] = Q[1] & ~iOpcode[31] & ~iOpcode[30] & ~iOpcode[29] & ~iOpcode[28] & iOpcode[27] & ~iOpcode[26];  
assign D[7] = Q[2];
assign D[8] = Q[3] & ~iOpcode[29];
assign D[9] = Q[3] & iOpcode[29];
assign D[10] = Q[8];
assign D[11] = Q[5];

/* output of control */
assign oPCWriteCond = Q[4];
assign oPCWrite = Q[0] | Q[6];
assign oIorD = Q[8] | Q[9];
assign oMemRead = Q[0] | Q[8];
assign oMemWrite = Q[9];
assign oMemtoReg = Q[10];
assign oIRWrite = Q[0];
assign oRegDst = Q[7];
assign oRegWrite = Q[7] | Q[10] | Q[11];
assign oALUSrcA = Q[2] | Q[3] | Q[4] | Q[5];
assign oALUSrcB[1] = Q[1] | Q[3] | Q[5];
assign oALUSrcB[0] = Q[0] | Q[1];
assign oALUOp[2] = Sub | Slt | Q[4];
assign oALUOp[1] = Add | Sub | Slt | Q[0] | Q[1] | Q[3] | Q[4];
assign oALUOp[0] = Slt | Q[5];
assign oPCSource[1] = Q[6];
assign oPCSource[0] = Q[4];

/* Function */
assign Add = Q[2] & iFunction[5] & ~iFunction[4] & ~iFunction[3] & ~iFunction[2] & ~iFunction[1] & ~iFunction[0];
assign Sub = Q[2] & iFunction[5] & ~iFunction[4] & ~iFunction[3] & ~iFunction[2] & iFunction[1] & ~iFunction[0];
assign Slt = Q[2] & iFunction[5] & ~iFunction[4] & iFunction[3] & ~iFunction[2] & iFunction[1] & ~iFunction[0];

endmodule

//////////////////////////////////////////////////////////////////////////////////
// 		D FlipFlop 		//////////////////////////////////////////	
//////////////////////////////////////////////////////////////////////////////////
module D_FF(D,C,Q,RESET);

input D, C,RESET;
output Q;
reg Q;
	
	always @ (posedge RESET or posedge C)
	begin
		if(RESET)
			Q <= 1'b0;
		else
			Q <= D;
	end
	
endmodule